package it.unisannio.pgridporting;

import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.Vector;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;

import android.app.Activity;
import android.util.Log;
import p2p.basic.GUID;
import p2p.basic.P2P;
import p2p.basic.P2PFactory;
import p2p.basic.Peer;
import p2p.storage.DataItem;
import p2p.storage.Query;
import p2p.storage.Storage;
import p2p.storage.StorageFactory;
import p2p.storage.Type;
import p2p.storage.TypeHandler;
import p2p.storage.events.SearchListener;
import pgrid.Constants;
import pgrid.interfaces.basic.PGridP2P;
import pgrid.interfaces.basic.PGridP2PFactory;
import pgrid.interfaces.storage.PGridStorageFactory;
import pgrid.network.protocol.ExchangeInvitationMessage;
import test.SimpleTypeHandler;
import test.WaitingArea;

public class PGridManager implements SearchListener {

	private P2PFactory p2pFactory = null;
	private P2P p2pService = null;
	private StorageFactory storageFactory = null;
	private Storage storage = null;
	private Type type = null;
	private BlockingQueue resultContacts=new LinkedBlockingQueue();
	private Collection mResultContacts= new Vector();
	Object sync = new Object();
	private boolean mSearchFinished;
	
	public PGridManager(String dirPath) {
		this.init(dirPath);
	}
	
	public void init(String dirPath) {

		p2pFactory = PGridP2PFactory.sharedInstance();
		//tv.append("Factory created \n");
		
		/**
		 * Debug
		 */
		Log.v("MyMessage", "Factory created");
		
		Properties properties = new Properties();
		//properties.setProperty(pgrid.Properties.BOOTSTRAP_HOSTS, "192.168.70.132:1806");
		properties.setProperty(PGridP2P.PROP_VERBOSE_MODE, "true");
		properties.setProperty(PGridP2P.PROP_LOCAL_PORT, "5000");
		properties.setProperty(pgrid.Properties.INIT_EXCHANGES, "true");
		properties.setProperty(pgrid.Properties.RESOLVE_IP, "false");
		try {
			PGridP2P.IP_HOST = InetAddress.getByAddress(new byte [] {(byte) 192, (byte) 168, (byte) 70, (byte) 102});
		} catch(UnknownHostException e) {
			e.printStackTrace();
		}
	
		/* 
		 * Con queste properties facciamo in modo che il file 
		 * di property e quello di log di pgrid finiscano in 
		 * una delle cartelle create.
		 */
		properties.setProperty(PGridP2P.PROP_PROPERTY_FILE, dirPath+System.getProperty("file.separator") + "myPropFile.prop");
		properties.setProperty(PGridP2P.PROP_LOG_FILE, dirPath+System.getProperty("file.separator") + "myLogFile.log");
		
		Logger log = Logger.getLogger("PGrid");
		log.setLevel(Level.OFF);
		
		String runMode = "Contacts_Searcher";
	
		p2pService = p2pFactory.createP2P(properties);
		storageFactory = PGridStorageFactory.sharedInstance();
		storage = storageFactory.createStorage(p2pService);
		Log.v("MyMessage","Service created \n");
	
		Peer myPeer=p2pService.getLocalPeer();
		Log.v("MyMessage", "Info peer: " + myPeer.getIP() + ":" + myPeer.getPort());

		type = storageFactory.createType("ContactType");
		TypeHandler handler = new SimpleTypeHandler(type);
		storageFactory.registerTypeHandler(type, handler);
		Log.v("MyMessage", "TypeHandler registered");
	}
	
	public boolean insert(String contact) {
		Vector items = new Vector();
		DataItem item;
		item = storageFactory.createDataItem(type, contact);
		Log.v("MyMessage", "DataItem created");
		Collection c = storage.getLocalDataItems();
		boolean alreadyInserted=false;
		Iterator it=c.iterator();
		while(it.hasNext()){
			DataItem currentItem=(DataItem) it.next();
			if(currentItem.equals(item))
					alreadyInserted=true;
		}
		
		if(alreadyInserted==false)
			items.add(item);
		storage.insert(items);
		
		storage.update(c);
		Log.v("MyMessage", "Items inserted");
		
		((PGridP2P)p2pService).setInitExchanges(true);
		return true;
	}
	
	public String[] searchCollection(String name) {
		Query query=storageFactory.createQuery(type, name);
		storage.search(query, this);
		waitUndefinitely();
		Collection tempContacts=new Vector();
		String[] resultStrings= new String[tempContacts.size()];
		int currentIndex=0;
		tempContacts.addAll(resultContacts);
		resultContacts.clear();
		if(tempContacts.isEmpty())
			return null;
		else{
			Iterator it=tempContacts.iterator();
			while(it.hasNext()){
				DataItem d= (DataItem) it.next();
				resultStrings[currentIndex++]=(String) d.getData();
			}			
		}
		return resultStrings;
	}
	
	public String search(String name) {
		final Query query = storageFactory.createQuery(type, name);
		mResultContacts.clear();
		storage.search(query, PGridManager.this);
		waitUndefinitely();
		Collection tempContacts = new Vector();
		tempContacts.addAll(mResultContacts);
		mResultContacts.clear();
		if(tempContacts.isEmpty())
			return null;
		else{
			Iterator it=tempContacts.iterator();
			while(it.hasNext()){
				DataItem d= (DataItem) it.next();
				return (String) d.getData();
				
			}
			return null;
		}
		
		/*
		t.start();
		Timer timer = new Timer();
		timer.schedule(new SearchTask(), 30 * 1000);
		storage
		Thread t = new Thread(new Runnable(){
			@Override
			public void run() {
				storage.search(query, PGridManager.this);
			}
		});   
		t.start();
		try{
			String result=(String) ((DataItem) resultContacts.take()).getData();
			
			resultContacts.clear();
			return result;
		}
		catch(Exception e){
			Log.v("MyMessage", "Search exception");
			resultContacts.clear();
			return null;
		}
	/*	waitUndefinitely();
		Collection tempContacts = new Vector();
		tempContacts.addAll(resultContacts);
		resultContacts.clear();
		if(tempContacts.isEmpty())
			return null;
		else{
			Iterator it=tempContacts.iterator();
			while(it.hasNext()){
				Object o=it.next();
				Log.v("MyMessage", "Class of result is " +o .getClass());
				return null;
			}
			return null;
		}*/
	}
	
	public boolean  delete(String contact) {
		return false;
	}
	
	private void waitUndefinitely() {
		synchronized (sync) {
			try {
				sync.wait();
			} catch (InterruptedException exc) {}
		}
	}
	
	private void signalWaiter() {
		synchronized (sync) {
				sync.notify();
		}
	}

	@Override
	public void newSearchResult(GUID guid, Collection results) {
		Log.v("MyMessage", "Found data item");
		//resultContacts.addAll(results);
		mResultContacts.addAll(results);
		
		//signalWaiter();
	}

	@Override
	public void noResultsFound(GUID guid) {
		Log.v("MyMessage", "No results found");
		//resultContacts.add(new Object());
		//signalWaiter();
	}

	@Override
	public void searchFailed(GUID guid) {
		Log.v("MyMessage", "Search Failed");
		//resultContacts.add(new Object());
		signalWaiter();
	}

	@Override
	public void searchFinished(GUID guid) {
		Log.v("MyMessage", "Search finished");
		signalWaiter();
	}

	@Override
	public void searchStarted(GUID guid, String message) { }

	class SearchTask extends TimerTask {

		@Override
		public void run() {
			Log.v("MyMessage", "Searchin timeout");
			resultContacts.add(new Object());
		}
		
	}
}



